#include<iostream>
using namespace std;
#include<unistd.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<vector>
#include<string>
#include<time.h>


#define NUM_PIPE 5

void makeseek(){
    srand((unsigned long)time(nullptr)^getpid());

}

typedef void (*func_t)();

void downloadtask(){
    cout<<"下载任务"<<getpid()<<endl;
    sleep(1);
}
void iotask(){
    cout<<"io任务"<<getpid()<<endl;
    sleep(1);
}
void flushtask(){
    cout<<"刷新任务"<<getpid()<<endl;
    sleep(1);
}

void loadtask(vector<func_t>* out){
    assert(out);
    out->push_back(downloadtask);//函数名称就是函数的地址
    out->push_back(iotask);
    out->push_back(flushtask);
}



//封装一个类，存放父进程的写端文件描述数，和子进程的pid
class subEp{
    public:
        subEp(pid_t subid,int write):_subid(subid),_write(write){
            cnt++;
            char buffer[1024];
            snprintf(buffer,sizeof buffer,"process:%d[pid:%d][fd:%d]",cnt,_subid,_write);
            _name = buffer;
        }
    public:
    static int cnt;//发送指令的个数
    string _name;//发送的指令，后面再进行封装
    pid_t _subid;
    int _write;
};
int subEp::cnt = 0;

void sendTask(const subEp& subprocess,int taskindex){
    cout<<"send task num:"<<taskindex<<"send to:"<<subprocess._name<<endl;
    int ret = write(subprocess._write,&taskindex,sizeof(taskindex));
   // assert(ret == sizeof(int));//写入4个字节
}

int reseTask(int readfd){
    //由于父进程写入的指令是4个字节，所以用int接收就可以
    int code = 0;
    ssize_t s = read(readfd,&code,sizeof(code));
    //assert(s == sizeof(int));
    if((int)s == sizeof(int)){
        return code;
    }else if(s <= 0){
        return -1;
    }else return 0;
}

void creatSubProcess(vector<subEp>* subs, vector<func_t>& funcMap){
    for(int i = 0;i<NUM_PIPE;i++){
        //创建管道文件
        int fds[2];
        int n = pipe(fds);
        assert(n==0);


        pid_t id = fork();
        assert(id >= 0);
        if(id == 0){
            //子进程接收父进程发送的指令
            close(fds[1]);
            //接收指令
            int commandcode = reseTask(fds[0]);
            //处理指令
            if(commandcode > 0 && commandcode < funcMap.size()){
                funcMap[commandcode]();
            }else if(commandcode == -1){
                break;
                //cout<<"出错了"<<endl;
            }
            //close(fds[0]);
           exit(0);
        }
        close(fds[0]);
        //exit(1);
        subEp sub(id,fds[1]);
        subs->push_back(sub);
    }

}

void loadBlanceControl(vector<subEp>& subs, vector<func_t>& funcMap,int taskcnt){
    //开始控制子进程
    bool ret = (taskcnt==0) ? true:false;
    int processnum = subs.size();
    int tasknum = funcMap.size();
    //实现随机分配任务给随机的子进程：负载均衡
    bool quit = false;
    while(true){
        int subIndex = rand()%processnum;
        int taskIndex= rand()%tasknum;
        sendTask(subs[subIndex],taskIndex);
        sleep(1);
        if(!ret){
            taskcnt--;
            if(taskcnt==0) break;
        }
        
    }
    //这里发送完任务就可以把所有的写端口关闭
    for(int i = 0;i<processnum;i++){
        close(subs[i]._write);
    }

}
void deleteprocess(vector<subEp> subs){
    for(int i = 0;i<subs.size();i++){
        waitpid(subs[i]._subid,nullptr,0);
        cout<<"等待成功:"<<subs[i]._subid<<endl;
    }
}

int main(){
    makeseek();
    vector<subEp> subs;
    //子进程处理的任务也要管理起来
    vector<func_t> funcMap;
    loadtask(&funcMap);

    //创建子进程通讯的管道，总共是5条
    creatSubProcess(&subs,funcMap);

    //父进程的范围
    //开始控制子进程
    int taskcnt = 20;
    loadBlanceControl(subs,funcMap,taskcnt);

    //回收空间
    deleteprocess(subs);

    return 0;
}